/*
 *   author : luwei
 * function : 游戏逻辑实现，canv绘制,组件自适应窗口,数据存储
 *  version : 1.0
 */

var canv, canv_ctx;
var timer;
var COLS = 8;
var ROWS = 8;
var CELL_SIZE = 100;
var RANDOMS = 1000;
var LINEWIDTH = 2;
var maxScore = 100;
var maxTime = 10;
var rand = [];
var curSpeed = 0.1;
var curPosi = ROWS;
var curScore = 0;
var curTimer = 0.00;
var curState = 0;
var curMode = "限时模式";

//初始化,
var initPane = function(){
    //动态设置宽度
    //按钮可用
    document.getElementById("start").disabled = false;
    //画出游戏的背景网格
    canv_ctx.beginPath();
    // 绘制横向网络对应的路径
    for (var i = 0; i <= ROWS; i++) {
        canv_ctx.moveTo(0, i * CELL_SIZE);
        canv_ctx.lineTo(COLS * CELL_SIZE, i * CELL_SIZE);
    }
    // 绘制竖向网络对应的路径
    for (var i = 0; i <= COLS; i++) {
        canv_ctx.moveTo(i * CELL_SIZE, 0);
        canv_ctx.lineTo(i * CELL_SIZE, ROWS * CELL_SIZE);
    }
    canv_ctx.closePath();
    // 设置笔触颜色
    canv_ctx.strokeStyle = "#aaa";
    // 设置线条粗细
    canv_ctx.lineWidth = LINEWIDTH;
    // 绘制线条
    canv_ctx.stroke();
}

//生成N个随机数
var rand = function(){
    for (var i = 0; i < RANDOMS; i++) {
    	rand[i] = Math.floor(Math.random() * COLS);
	}
}
//向下移动
var offsetY = 0 ;
var moveDown = function(){
    if(curMode === "竞速模式" && curState === 1){
        //计算往下的偏移距离 
        offsetY += curSpeed;
        //当偏移超过一个格子时
    }
    if(offsetY >= CELL_SIZE){
        offsetY = offsetY - CELL_SIZE;
        curPosi++;
        //如果过了底线的格子没有被点击了,游戏结束
        if(!clickedFlag[curPosi-ROWS-1]) {
            suspendGame();
            gameOver();
        }  
    }
    //绘制背景方格
    canv_ctx.beginPath();
    // 绘制横向网络对应的路径
    for (var i = 0; i <= ROWS; i++) {
        canv_ctx.moveTo(0, i * CELL_SIZE + offsetY);
        canv_ctx.lineTo(COLS * CELL_SIZE, i * CELL_SIZE + offsetY);
    }
    canv_ctx.closePath();
    // 设置笔触颜色
    canv_ctx.strokeStyle = "#aaa";
    // 设置线条粗细
    canv_ctx.lineWidth = LINEWIDTH;
    // 绘制线条
    canv_ctx.stroke();

    //绘制方块
    for (var j = -1; j < ROWS; j++) {
        for(var k = 0; k < COLS; k++){
            //绘制黑块
            if(rand[curPosi-j-1] === k && !clickedFlag[curPosi-j-1]){
                canv_ctx.fillStyle = "black";
            }else if(rand[curPosi-j-1] === k && clickedFlag[curPosi-j-1]){
                canv_ctx.fillStyle = "red";
            }else{
                canv_ctx.fillStyle = "white";
            }
            canv_ctx.fillRect(k * CELL_SIZE+LINEWIDTH/2 , j * CELL_SIZE+LINEWIDTH/2 + offsetY, CELL_SIZE-LINEWIDTH, CELL_SIZE-LINEWIDTH);
        }
    }
}
//打印对应的黑色方格
var initPrint = function() {
	//设置填充色为黑色
    canv_ctx.fillStyle = "black";
	//遍历每一行，使相应的位置涂上黑色
    for (var j = 0; j < ROWS; j++) {
        canv_ctx.fillRect(rand[curPosi - j - 1] * CELL_SIZE+LINEWIDTH/2, j * CELL_SIZE+LINEWIDTH/2, CELL_SIZE-LINEWIDTH, CELL_SIZE-LINEWIDTH);
    }
}
//消除之前产生的黑色方格
var clear = function() {
	//设置为白色，即为消除
    canv_ctx.fillStyle = "white";
    for (var j = 0; j < ROWS; j++) {
        canv_ctx.fillRect(rand[curPosi - j - 1] * CELL_SIZE+LINEWIDTH/2, j * CELL_SIZE+LINEWIDTH/2, CELL_SIZE-LINEWIDTH, CELL_SIZE-LINEWIDTH);
    }
}
//当按键错误时，在错误位置变红提示
var pressErr = function(keyCode){
		canv_ctx.fillStyle="red";
		canv_ctx.fillRect(keyCode*CELL_SIZE+LINEWIDTH/2,(ROWS-1)*CELL_SIZE+LINEWIDTH/2,CELL_SIZE-LINEWIDTH,CELL_SIZE-LINEWIDTH);
	}

//当点击了错误的位置后，在相应位置出现红块提示
var colErrErr , rowErrErr;
var clickErr = function(){
	canv_ctx.fillStyle="red";
	canv_ctx.fillRect(colErr*CELL_SIZE+LINEWIDTH/2,rowErr*CELL_SIZE+LINEWIDTH/2,CELL_SIZE-LINEWIDTH,CELL_SIZE-LINEWIDTH);
	}

//存储分数
var storeScore = function(){
        //如果当前模式没有排名，则创建
        if(localStorage.getItem(curMode) == null){
            //初始化结构化value
            var rankJSON = {
                rank0 : curMode==="限时模式"?curScore:curTimer.toFixed(2),
                rank1 : -1,
                rank2 : -1,
                rank3 : -1,
                rank4 : -1,
                rank5 : -1,
                rank6 : -1,
                rank7 : -1,
                rank8 : -1,
                rank9 : -1     //注意此处没有逗号
            };
            //将json对象作为value存入localStorage
            localStorage.setItem(curMode,JSON.stringify(rankJSON));
        //如果当前模式有排名，则读出排名，在排名
        }else{
            //取出value并且转换成json对象
            var rankJSON = JSON.parse(localStorage.getItem(curMode));
            //插入标志
            var insertflag = false;
            //临时变量，保存将要替换的数据
            var temp_pre;
            var temp_self;
            //遍历json对象
            for(idx in rankJSON){
                //如果没插入且时间比对应的成绩快，则插入
                if( (curMode==="限时模式"?rankJSON[idx] <= curScore : rankJSON[idx] >= curTimer.toFixed(2)
                    || rankJSON[idx] === -1) && !insertflag ){
                   temp_pre = rankJSON[idx];
                   rankJSON[idx] = (curMode === "限时模式"?curScore:curTimer.toFixed(2)); 
                   insertflag = true;
                //如果能够进入排行榜,把之后的排名往后推
                }else if(insertflag){
                    temp_self = rankJSON[idx];
                    rankJSON[idx] = temp_pre;
                    temp_pre = temp_self;
                }
            }
            //存入localStorage
            localStorage.setItem(curMode,JSON.stringify(rankJSON));
        }
}

//显示排行榜
var showRank = function(){
    var noRank;
    //得到rank DIV组件
    var rankDiv = document.getElementById("rank");
    //得到rankName div组件
    var rankName = document.getElementById("rankName");
    //设置模式名字
    rankName.innerHTML = curMode;
    //创建span数组
    var spans = [];
    //清空
    if(document.getElementById("tip") !== null){
        rankDiv.removeChild(document.getElementById("tip"));
    }
    for(var i=0;i<10;i++){
        if(document.getElementById("rank"+i) !== null){
            rankDiv.removeChild(document.getElementById("rank"+i));
        }else{
            break;
        }
    }
    //如果该模式有localStorage 
    if(localStorage.getItem(curMode) != null ){
        var rank = JSON.parse(localStorage.getItem(curMode));
        var i = 0;
        //遍历
        for(idx in rank){
            //分数有效
            if(rank[idx] !== -1 ){
                spans[i] = document.createElement("p");
                spans[i].innerHTML ="第" + (i+1) + "名" + ':' + rank[idx] + (curMode==="竞速模式"?'s':'m');
                spans[i].setAttribute("id","rank"+i);
                rankDiv.appendChild(spans[i]);
            }
            i++;
        }
    //如果没有，tip
    }else{
       noRank = document.createElement("span");
       noRank.innerHTML = "该模式暂时没有排行榜";
       noRank.setAttribute("id","tip");
       rankDiv.appendChild(noRank);
    }
}

//整合代码，点击正确位置，或者敲击正确键位
var next = function(){
    //当前分数加1且写入Html中。
     document.getElementById("curScore").innerHTML = (curScore += 1);
     //消除黑块
	 clear();
     //如果到达终点
     if(curPosi - ROWS + 1 === RANDOMS ){
        //停止计时
        timer.stopTimer();
        //设置状态为结束
        curState = -1;
        //设置按钮状态
        document.getElementById("start").innerHTML = "Nice!";
        document.getElementById("start").disabled = true;
        storeScore();
     //如果没有到达终点，继续走下一步
     }else{
         //当前位置加1
         curPosi++;
         //打印黑块
         initPrint();
        }
	}
//监听窗口大小改变事件
window.onresize = reSize = function(){
    //如果是无限模式，改变了大小之前要暂停
    //这样改变了游戏状态.
    if(curMode == "竞速模式" && curState === 1){
        suspendGame();
    }
    //得到各个主要组件
    var infoDiv = document.getElementById("info");
    var rankDiv = document.getElementById("rank");
    var mainBoxDiv = document.getElementById("mainBox");
    var configDiv = document.getElementById("config");
    var optionDiv = document.getElementById("option");
    //得到当前浏览器窗口的大小
    var clientW = window.innerWidth;
    var clientH = window.innerHeight;
    //设置各个组件的大小
    infoDiv.style.width = clientW * 0.2 + "px";
    infoDiv.style.height = clientH * 0.2 + "px";
    rankDiv.style.width = clientW * 0.2 + "px";
    rankDiv.style.height = clientH * 0.7 + "px";
    mainBoxDiv.style.width = clientW * 0.5 + "px";
    mainBoxDiv.style.height = clientH * 0.95 + "px";
    configDiv.style.width = clientW * 0.2 + "px";
    configDiv.style.height = clientH * 0.95 + "px";
    //option
    optionDiv.style.height = clientH * 0.61 - 150 + "px";
    //canvans的大小由网格计算得出
    var width,height;
    width = clientW * 0.5 * 0.9/COLS;
    height = clientH * 0.95 * 0.9/ROWS;
    CELL_SIZE = width > height ? height : width ;
    canv.width = COLS * CELL_SIZE;
    canv.height = ROWS * CELL_SIZE;
    //设置各个组件的margin,都一样，连续赋值
    infoDiv.style.margin = configDiv.style.margin = mainBoxDiv.style.margin = 
        rankDiv.style.margin = clientH*0.1/4 + "px " + clientW*0.1/6 + "px";
    canv.style.margin = (clientH * 0.95 - canv.height)/2 + "px " + (clientW * 0.5 - canv.width)/2 + "px";   

    //设置各个组件的位置
    info.left = 0 + "px";
    info.style.top = 0 + "px";
    rankDiv.style.left = 0 + "px";
    rankDiv.style.top = clientH*0.25 + "px";
    mainBoxDiv.style.left = clientW*7/30 + "px";
    mainBoxDiv.style.top = 0 + "px";
    configDiv.style.left = clientW*23/30 + "px";
    configDiv.style.top = 0 + "px";
    //加个阴影
    canv.style.boxShadow = "0px -1px 10px 1px black";
    //貌似改变了canvas的大小后，画布会重置，只能重新绘制了
    //幸亏函数耦合度小。
    initPane(); 
    //这个会往下移动一次，不好，算是延迟吧
    moveDown();
}

//开始游戏
var startGame = function(){
     //改变状态变量
    curState = 1;
    document.getElementById("start").innerHTML = "Stop!";
    if(curMode === "限时模式"){    
       timer.startTimer();
    }else if(curMode === "竞速模式"){ 
       timer.startTimer();
       mTimerInstance = setInterval("moveDown()",10);
    }
}
//暂停游戏
var suspendGame = function(){
    //改变状态变量
    curState = 0;
    document.getElementById("start").innerHTML = "Start!";
    if(curMode === "限时模式"){  
        timer.stopTimer();
    }else if(curMode === "竞速模式"){
        timer.stopTimer();
        clearInterval(mTimerInstance);
    }    
}

var repaly = function(){
    clickedFlag = [];
    curTimer = 0;
    curScore = 0;
    offsetY = 0;
    curSpeed = 0.1;
    curState = 0;
    curPosi = ROWS;
    rand();
    moveDown();
    startGame();
}
//游戏结束
var gameOver = function(){
    curState = -1;
    document.getElementById("start").innerHTML = "Repaly!";
}

//游戏通过
var gamePass = function(){
    curState = -1;
    timer.stopTimer();
    storeScore();
    showRank();
    document.getElementById("start").innerHTML = "Repaly!";
}
// 为窗口的按键事件绑定事件监听器,最多支持八键
window.onkeydown = function(evt) {
    //如果按键为空格，转换游戏状态
    if (evt.keyCode == 32 && curState != -1) {
        switchState();
    }
    //如果正在游戏，则可以响应键盘事件
    if(curState === 1){
        switch (evt.keyCode) {
        	//当按键为a时
            case 65:
                rand[curPosi - ROWS] === 0?next():pressErr(0);
                break;
        	//当按键为s时
            case 83:
        	 	rand[curPosi - ROWS] === 1?next():pressErr(1);
                break;
        	//当按键为d时
            case 68:
        		 rand[curPosi - ROWS] === 2?next():pressErr(2);
                break;
        	//当按键为f时
            case 70:
        		 rand[curPosi - ROWS] === 3?next():pressErr(3);
                break;
            //当按键为j时
            case 74:
                rand[curPosi - ROWS] === 4?next():pressErr(4);
                break;
            //当按键为k时
            case 75:
                rand[curPosi - ROWS] === 5?next():pressErr(5);
                break;
            //当按键为l时
            case 76:
                 rand[curPosi - ROWS] === 6?next():pressErr(6);
                break;
            //当按键为R时
            case 82:
                curMode === "竞速模式"?curSpeed+=0.1:curSpeed;
                break;
            //当按键为U时
            case 85:
                curMode === "竞速模式"? curSpeed>0 ? curSpeed-=0.1:curSpeed:curSpeed;
                break;
            //当按键为;时
            case 186:
                 rand[curPosi - ROWS] === 7?next():pressErr(7);
                break;
        }
    }
}

//当按键松开时，还原
window.onkeyup = function(evt){
    if(curState === 1){
    	//替换，减少三元表达式的长度
    	var k = evt.keyCode;
    	//根据按键得到位置，注意，我将默认值设为了1000，在某些情况下可能引起bug
    	var key =  (k===65?0:k===83?1:k===68?2:k===70?3:k===74?4:k===75?5:k===75?6:k===76?7:100);
    	canv_ctx.fillStyle= (rand[curPosi - ROWS] === key?"black":"white");
    	canv_ctx.fillRect(key*CELL_SIZE+LINEWIDTH/2,(ROWS-1)*CELL_SIZE+LINEWIDTH/2,CELL_SIZE-LINEWIDTH,CELL_SIZE-LINEWIDTH);
    }
}
	
//绑定鼠标事件
var clickedFlag = [];
window.onmousedown = function(evt) {
        if (curState === 1) {  
            //如果当前模式为限时模式
            if(curMode === "限时模式"){
                //getBoundingClientRect()获得组件在当前窗口的位置，有四个属性left、top、right和bottom 非常棒的属性！
                //offsetLeft绝对的位置
                //获得点击的行和列 
                colErr = Math.floor((evt.clientX-canv.getBoundingClientRect().left)/CELL_SIZE);
                rowErr = Math.floor((evt.clientY-canv.getBoundingClientRect().top)/CELL_SIZE);
            	// 当点击的位置的x坐标判断,stupid codes;
                // var v1 = evt.clientX <= CELL_SIZE + canv.getBoundingClientRect().left + rand[curPosi - COLS] * CELL_SIZE 
            	// 	  && evt.clientX >= canv.getBoundingClientRect().left + rand[curPosi - COLS] * CELL_SIZE;
            	// //点击的位置的y坐标判断
                // var v2 = evt.clientY <= CELL_SIZE + canv.getBoundingClientRect().top + (ROWS-1) * CELL_SIZE 
            	//    && evt.clientY >= canv.getBoundingClientRect().top + (ROWS-1) * CELL_SIZE;
            	//当点击的位置在方框内时
                if (rand[curPosi-rowErr-1] === colErr) {
                        next();
                } else {
                        clickErr();
                }   
            //如果当前模式为竞速模式
        }else if(curMode === "竞速模式"){
            //获得点击的行和列 
            colErr = Math.floor((evt.clientX-canv.getBoundingClientRect().left)/CELL_SIZE);
            rowErr = Math.floor((evt.clientY-canv.getBoundingClientRect().top-offsetY)/CELL_SIZE);
            //如果点击正确，分数加1
            if(
                    (rand[curPosi-1-rowErr] === colErr && clickedFlag[curPosi - rowErr -2]) ||
                    (rand[curPosi-1-rowErr] === colErr  && curPosi - rowErr -1 === 0)
                ){
                    clickedFlag[curPosi-rowErr-1] = true;
                document.getElementById("curScore").innerHTML = curScore++;
                if(curScore-1 === maxScore ){
                    gamePass();
                }
            }  
        }
    }
}

//绑定鼠标事件
window.onmouseup = function(evt) {
    //注意数组的下标，curPosi初始值为4!!
    if (curState === 1) {
        canv_ctx.fillStyle  = rand[curPosi-rowErr-1]===colErr ?"black":"white";
        canv_ctx.fillRect(colErr*CELL_SIZE+LINEWIDTH/2,rowErr*CELL_SIZE+LINEWIDTH/2,CELL_SIZE-LINEWIDTH,CELL_SIZE-LINEWIDTH);
    }
}
var switchState = function(){
    //如果当前状态为暂停
    if(curState === 0 ){
        startGame();
    //如果当前状态为正在玩
    }else if(curState === 1){
        suspendGame();
    }else if(curState === -1){
        repaly();
    }
}

var setMatrix = function(){
   ROWS = document.getElementById("rows").value;
   COLS = document.getElementById("cols").value;
   rand();
   reSize();
}

var createPane = function(){
    var speedUpButton,speedDownButton,tenScend,halfMinute,oneMinute;
    if (curMode === "竞速模式") {
        //删除由另一个模式创建的面板
        if(document.getElementById("tenScend") !== null){
            document.getElementById("option").removeChild(document.getElementById("tenScend"));
            document.getElementById("option").removeChild(document.getElementById("halfMinute"));
            document.getElementById("option").removeChild(document.getElementById("oneMinute"));
        }
        //创建竞速模式选项面板
        speedUpButton = document.createElement("button");
        speedDownButton = document.createElement("button");
        speedUpButton.innerHTML = "加速(R)";
        speedDownButton.innerHTML = "减速(U)";
        speedUpButton.setAttribute("id","speedUp");
        speedDownButton.setAttribute("id","speedDown");
        document.getElementById("option").appendChild(speedUpButton);
        document.getElementById("option").appendChild(speedDownButton);
        //设置功能
        speedUpButton.onclick = function(){
            curSpeed += 0.1;
        }
        speedDownButton.onclick = function(){
            if(curSpeed > 0){
                curSpeed -= 0.1;
            }
        }
    }else if(curMode === "限时模式"){
        if(document.getElementById("speedUp") !== null){
            //删除由另一个模式创建的面板
            document.getElementById("option").removeChild(document.getElementById("speedDown"));
            document.getElementById("option").removeChild(document.getElementById("speedUp"));
        }
        //创建竞速模式选项面板
        tenScend = document.createElement("button");
        halfMinute = document.createElement("button");
        oneMinute = document.createElement("button");
        tenScend.innerHTML = "10s";
        halfMinute.innerHTML = "30s";
        oneMinute.innerHTML = "60s";
        tenScend.setAttribute("id","tenScend");
        halfMinute.setAttribute("id","halfMinute");
        oneMinute.setAttribute("id","oneMinute");
        document.getElementById("option").appendChild(tenScend);
        document.getElementById("option").appendChild(halfMinute);
        document.getElementById("option").appendChild(oneMinute);
        //设置功能
        tenScend.onclick = function(){
            maxTime = 10;
        }
        halfMinute.onclick = function(){
            maxTime = 30;
        }
        oneMinute.onclick = function(){
            maxTime = 60;
        }
    }
        //刷新排行榜
        showRank();
}
//加载模式1
var loadMode1 = function(){
    if(curMode !== "竞速模式"){
        curMode = "竞速模式";
        createPane();
    }
}
//加载模式2
var loadMode2 = function(){
    if(curMode !== "限时模式"){
        curMode = "限时模式";
        createPane();
    }
}
var start = function(){ 
    //创建Timer对象
    timer = new Timer();
    //为点击按钮绑定函数
    document.getElementById("start").onclick = switchState;
    document.getElementById("mode1").onclick = loadMode1;
    document.getElementById("mode2").onclick = loadMode2;
    //设置行列数
    document.getElementById("set").onclick = setMatrix;
    //
    canv = document.createElement("canvas");
    canv_ctx = canv.getContext("2d");
    reSize();
    document.getElementById("mainBox").appendChild(canv);
}
//计时器计时
var Timer = function(){
    //如果是非chrome浏览器,且支持worker
    //为了防止卡顿，创建子线程计时
    if(window.navigator.userAgent.indexOf("Chrome") <= -1 && typeof(Worker) !== "undefined" ){
        Timer.time_worker = new Worker("timer.js");
         //开始计时
        this.startTimer = function(){
            //JSON创建对象
            data = {
                command : "start"
            };
            //向子进程传送数据
            Timer.time_worker.postMessage(JSON.stringify(data));
            //接收子进程传送过来的数据
            Timer.time_worker.onmessage = function(event){
                curTimer = event.data;
                document.getElementById("timer").innerHTML = curTimer.toFixed(2);
            }
        }
        //停止计时
        this.stopTimer = function(){
            //JSON创建对象
            data = {
                command : "stop"
            }; 
            //向子进程传送数据
            Timer.time_worker.postMessage(JSON.stringify(data));
        }
    //如果是chrome的解决方案,或者不支持Worker
    }else{
        this.startTimer = function(){
            timerInstance = setInterval("timeAdd()",10);
        }
        this.stopTimer = function(){
            clearInterval(timerInstance);
        }
    }
}

//为chrome创建计时函数
var timeAdd = function(){
    document.getElementById("timer").innerHTML = (curTimer += 0.01).toFixed(2);
    if(curMode === "限时模式"){
        if(curTimer+0.01 >= maxTime ){
            suspendGame();
            gamePass();
        }
    } 
}
//在页面加载后，创建canvas等操作，必须等页面加载完才能调用
//方法，否则会出现得不到相应组件的问题。
window.onload = function() { 
    start();
    initPane();
    rand();
    initPrint();
    showRank();
    createPane();
}
//窗口获得焦点
window.focus();